home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / driverss.zip / ISOLINK.ASM < prev    next >
Assembly Source File  |  1991-01-31  |  51KB  |  1,539 lines

  1.     page 54,132
  2. ; Packet driver for BICC Data Networks' ISOLINK 4110-2 ethernet
  3. ; controller, written by
  4. ;       Rainer Toebbicke
  5. ;       European Organisation of Nuclear Research (CERN)
  6. ;       Geneva, Switzerland
  7. ; based on the "generic" packet driver by Russell Nelson.
  8.  
  9. version equ     1               ;this is the minor version
  10.  
  11.         include defs.asm        ;SEE ENCLOSED COPYRIGHT MESSAGE
  12.  
  13.  
  14.  
  15. ; BICC ISOLINK card constants
  16.  
  17.  
  18.  
  19.         .286c                   ; we are at least on a 80286!
  20.  
  21.  
  22. code    segment para public
  23.         assume  cs:code, ds:code
  24.         public  begin   ;makes us appear in the link map
  25. begin   equ     $       ;used for alignment operations below
  26.  
  27. ;Lance initialisation block, must be on word boundary
  28.  
  29. IBmode          dw      00h             ;mode word
  30. IBpadr          db      6 dup (0)       ;physical addr
  31. IBladrf         db      8 dup (0ffh)    ;logical addr filter
  32. IBrdraL         dw      0               ;Receive Descr Ring ptr
  33. IBrdraH         dw      0
  34. IBrdraHF        equ     byte ptr IBrdraH+1
  35. IBtdraL         dw      0               ;Transmit Descr Ring ptr
  36. IBtdraH         dw      0
  37. IBtdraHF        equ     byte ptr IBtdraH+1
  38.  
  39.  
  40. CSR0            equ     0
  41. c0_FIX          equ     0000h
  42. c0_ERR          equ     8000h
  43. c0_BABL         equ     4000h
  44. c0_CERR         equ     2000h
  45. c0_MISS         equ     1000h
  46. c0_MERR         equ     0800h
  47. c0_RINT         equ     0400h
  48. c0_TINT         equ     0200h
  49. c0_ErrClear     equ     c0_BABL+c0_CERR+c0_MISS+c0_MERR
  50.  
  51. c0_IDON         equ     0100h
  52. c0_INTR         equ     0080h
  53. c0_INEA         equ     0040h
  54. c0_RXON         equ     0020h
  55. c0_TXON         equ     0010h
  56. c0_TDMD         equ     0008h
  57. c0_STOP         equ     0004h
  58. c0_STRT         equ     0002h
  59. c0_INIT         equ     0001h
  60.  
  61.  
  62. CSR1            equ     1
  63. CSR2            equ     2
  64. CSR3            equ     3
  65.  
  66.  
  67.  
  68. RD              struc                   ;Receive descriptor
  69. RBadrL          dw      0
  70. RBadrH          dw      0
  71. RBbcnt          dw      0               ;buffer size
  72. RBmcnt          dw      0               ;packet size
  73. RD              ends
  74.  
  75. RBflags         equ     byte ptr RBadrH+1
  76. RBown           equ     080h            ;1=owned by Lance, 0=by host
  77. RBerr           equ     040h            ;error summary bit
  78. RBfram          equ     020h
  79. RBoflo          equ     010h
  80. RBcrc           equ     008h
  81. RBbuff          equ     004h
  82. RBstp           equ     002h            ;start of packet
  83. RBenp           equ     001h            ;end of packet
  84.  
  85. TD              struc                   ;Transmit descriptor
  86. TBadrL          dw      0
  87. TBadrH          dw      0
  88. TBbcnt          dw      0               ;buffer size
  89. TBtdr           dw      0               ;more flags
  90. TD              ends
  91.  
  92. TBflags         equ     byte ptr TBadrH+1
  93. TBown           equ     080h            ;1=owned by Lance, 0=by host
  94. TBerr           equ     040h            ;error summary bit
  95. TBstp           equ     002h            ;Start of packet
  96. TBenp           equ     001h            ;End of packet
  97. TBbcntF         equ     byte ptr TBbcnt+1
  98.  
  99.  
  100.         public  int_no
  101. int_no  dw      10,0                     ;must be four bytes long for get_number.
  102.  
  103.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  104. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  105. driver_type     db      5               ;from the packet spec
  106. driver_name     db      'ISOLINK',0     ;name of the driver.
  107. driver_function    db    2
  108. parameter_list    label    byte
  109.     db    1    ;major rev of packet driver
  110.     db    9    ;minor rev of packet driver
  111.     db    14    ;length of parameter list
  112.     db    EADDR_LEN    ;length of MAC-layer address
  113.     dw    GIANT    ;MTU, including MAC headers
  114.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  115.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  116.     dw    0    ;(# of successive xmits) - 1
  117. int_num    dw    0    ;Interrupt # to hook for post-EOI
  118.             ;processing, 0 == none,
  119.  
  120.     extrn    sys_features: byte
  121.  
  122.         public  rcv_modes
  123. rcv_modes       dw      7         ;number of receive modes in our table.
  124.                 dw      0
  125.                 dw      rcv_mode_1
  126.                 dw      0
  127.                 dw      rcv_mode_3
  128.                 dw      0,0
  129.                 dw      rcv_mode_6
  130.  
  131.  
  132.  
  133. rbfstart        dw      FirstDescr      ;1st Rcv buffer descr
  134. rbfcurr         dw      ?
  135. tbfstart        dw      ?               ;1st Xmit buffer descr
  136. tbfcurr         dw      ?
  137. tbfend          dw      ?               ;end of Xmit buffers
  138.  
  139. xmt_buffsz_r    dw      ?               ;xmit buffer sizes
  140. xmt_buffsz_rn   dw      ?               ;same, but times -1
  141. pklen           dw      ?               ;length of packet
  142. pklen_rem       dw      ?               ;remaining to be received
  143. rcv_csr0        dw      ?
  144. rcvbuffp        dd      ?
  145.  
  146.  
  147. RAP             dw      0               ;Register Address Port
  148. RDP             dw      0               ;Register Data Port
  149.  
  150. options         db      0
  151. options_HMA     equ     40h             ;running in HMA
  152.  
  153. word_16         dw      16
  154.  
  155.  
  156.                 extrn   count_out_err:near, count_in_err:near
  157.  
  158.  
  159. seg2lin         proc    near
  160. ; convert (ax:dx=offset:segment) to linear address (ax:dx=low:high)
  161.                 push    bx
  162.                 push    ax              ;save offset
  163.                 mov     ax,dx
  164.                 mul     word_16         ;segment to linear address
  165.                 pop     bx
  166.                 add     ax,bx           ;plus offset
  167.                 adc     dx,0
  168.                 pop     bx              ;restore
  169.                 ret
  170. seg2lin         endp
  171.  
  172.  
  173. lin2seg         proc    near
  174. ; convert linear addr (ax:dx=low:high) to (ax:dx=offset:segment)
  175. ; with minimal offset to avoid wrap-around problems
  176.  
  177. ; the 80286 can address 0-10ffefh in real mode:
  178.                 cmp     dl,010h         ;over 1 Megabyte?
  179.                 je      l2sHMA          ;yes, segment is 0FFFFh
  180.                 push    ax
  181.                 shr     ax,4            ;convert to paragraphs
  182.                 shl     dx,4+8
  183.                 or      dx,ax           ;segment ok
  184.                 pop     ax
  185.                 and     ax,0fh          ;offset
  186.                 ret
  187.  
  188.  
  189. l2sHMA:
  190. ; effectively subtract 0ffff0h from the linear address to form the
  191. ; offset:
  192.                 mov     dx,0ffffh       ;this we know already
  193.                 sub     ax,0fff0h       ;only have to do low order word
  194.                 ret
  195. lin2seg         endp
  196.  
  197.  
  198. ; write bx to Lance control & status reg [ax]
  199. wrcsr0          proc    near
  200.                 xor     ax,ax           ;write to CSR0
  201. wrcsr:                                  ;CSR in ax
  202.                 mov     dx,RAP          ;address CSR
  203.                 out     dx,ax
  204.                 mov     dx,RDP          ;data port
  205.                 mov     ax,bx
  206.                 out     dx,ax
  207.                 ret
  208. wrcsr0          endp
  209.  
  210.  
  211. ; read Lance control reg [ax]
  212. rdcsr0          proc    near
  213.                 xor     ax,ax           ;read CSR 0
  214. rdcsr:                                  ;CSR in ax
  215.                 mov     dx,RAP
  216.                 out     dx,ax
  217.                 mov     dx,RDP
  218.                 in      ax,dx
  219.                 ret
  220. rdcsr0          endp
  221.  
  222.  
  223. rcv_nxt_d       proc    near
  224. ; release current and advance to next receive descriptor
  225.                 mov     RBflags[bx],RBown       ;give buffer to Lance
  226.                 add     bx,8
  227.                 cmp     bx,tbfstart     ;end of ring?
  228.                 jb      rcv_nxt_ok      ;no...
  229.                 mov     bx,rbfstart     ;restart at first descriptor
  230. rcv_nxt_ok:
  231.                 mov     rbfcurr,bx
  232.                 ret
  233. rcv_nxt_d       endp
  234.  
  235.  
  236. xmt_nxt_d       proc    near
  237. xmt_nxt_d       endp
  238.  
  239.  
  240. wait_own_0      proc    near
  241. ; wait for "own" bit in descriptor [bx] to clear
  242.                 test    TBflags[bx],TBown
  243.                 jnz     wo_wait                 ;no, have to wait
  244.                 ret
  245.  
  246. wo_wait:
  247.                 push    cx                      ;save reg
  248.                 mov     cx,0ffffh
  249. wo_lp1:
  250.                 test    TBflags[bx],TBown
  251.                 jz      wo_clear                ;ok...
  252.                 loop    wo_lp1
  253.  
  254. wo_clear:
  255.                 pop     cx
  256.                 ret
  257. wait_own_0      endp
  258.  
  259.  
  260. rcv_getaddr     proc    near
  261. ; obtain buffer addr from descriptor [bx]
  262.                 mov     ax,RBadrL[bx]
  263.                 mov     dx,RBadrH[bx]
  264.                 call    lin2seg
  265.                 mov     word ptr rcvbuffp,ax
  266.                 mov     word ptr rcvbuffp+2,dx
  267.                 ret
  268. rcv_getaddr     endp
  269.  
  270.     public    as_send_pkt
  271. ; The Asynchronous Transmit Packet routine.
  272. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  273. ;   interrupts possibly enabled.
  274. ; Exit with nc if ok, or else cy if error, dh set to error number.
  275. ;   es:di and interrupt enable flag preserved on exit.
  276. as_send_pkt:
  277.     ret
  278.  
  279.     public    drop_pkt
  280. ; Drop a packet from the queue.
  281. ; Enter with es:di -> iocb.
  282. drop_pkt:
  283.     assume    ds:nothing
  284.     ret
  285.  
  286.     public    xmit
  287. ; Process a transmit interrupt with the least possible latency to achieve
  288. ;   back-to-back packet transmissions.
  289. ; May only use ax and dx.
  290. xmit:
  291.     assume    ds:nothing
  292.     ret
  293.  
  294.  
  295.         public  send_pkt
  296. send_pkt        proc    near
  297. ;enter with ds:si -> packet, cx = packet length.
  298. ;exit with nc if ok, or else cy if error, dh set to error number.
  299.         assume  ds:nothing
  300.                 push    ds              ;save packet segment
  301.                 push    cs
  302.                 pop     ds
  303.                 assume  ds:code
  304.  
  305. ; packet must be at least 64 bytes long (with fcs)...
  306.                 cmp     cx,RUNT
  307.                 jnl     send_L_ok
  308.                 mov     cl,RUNT
  309. send_L_ok:
  310.  
  311. ; get next buffer descriptor
  312.                 mov     bx,tbfcurr
  313.                 call    wait_own_0      ;wait until it's free
  314.  
  315. ; If the next buffer is big enough to hold the packet, we will
  316. ; copy the packet and send it out.
  317. ; Otherwise we send it from the user's buffer but then have to
  318. ; wait until it is sent out.
  319. ; This may speed up fast machines on the expense of some memory
  320.  
  321.                 cmp     cx,xmt_buffsz_r ;longer than our buffers?
  322.                 jng     send_copy       ;no, copy the packet
  323.  
  324. send_user_buff:                         ;send from user's buffer
  325.                 mov     ax,si           ;input buffer addr
  326.                 pop     dx              ;segment
  327.                 call    seg2lin         ;convert to linear addr
  328.                 push    TBadrL[bx]      ;save original buffer address
  329.                 push    TBadrH[bx]      ;...
  330.                 mov     TBadrL[bx],ax
  331.                 mov     TBadrH[bx],dx
  332.                 jmp     short send_send
  333.  
  334. send_copy:
  335.                 mov     ax,TBadrL[bx]
  336.                 mov     dx,TBadrH[bx]   ;buffer address
  337.                 call    lin2seg         ;convert to offset:segment
  338.                 mov     es,dx
  339.                 mov     di,ax
  340.                 pop     ds              ;restore packet segment
  341.                 assume  ds:nothing
  342.                 push    cx              ;save length
  343.  
  344. ; The packet is copied two bytes at a time, starting with the even(!)
  345. ; address of the destination buffer.
  346.                 shr     cx,1            ;convert to words, can't be zero
  347.                 rep     movsw           ;copy buffer
  348.                 jnc     send_moved      ;was original length even?
  349.                 movsb
  350. send_moved:
  351.                 pop     cx
  352.                 push    cs
  353.                 pop     ds              ;restore ds
  354.                 assume  ds:code
  355.  
  356. send_send:
  357.                 neg     cx              ;length in two's complement
  358.                 mov     TBbcnt[bx],cx
  359.                 or      TBflags[bx],TBown+TBstp+TBenp
  360.                 push    bx              ;save ring entry address
  361.                 mov     bx,c0_TDMD+c0_INEA
  362.                 call    wrcsr0          ;start transmitter immediately
  363.                 pop     bx              ;restore ring entry addr
  364.                 xor     al,al           ;assume no error
  365.                 cmp     cx,xmt_buffsz_rn ;was this a big buffer?
  366.                 jnl     send_next       ;no, all done
  367.  
  368.                 call    wait_own_0      ;wait for send ok
  369.                 mov     al,TBflags[bx]  ;save flags
  370.                 mov     cx,xmt_buffsz_rn ;original buffer size negated
  371.                 pop     TBadrH[bx]
  372.                 pop     TBadrL[bx]
  373.                 mov     TBbcnt[bx],cx
  374.  
  375.  
  376.  
  377. ; advance to next transmit descriptor
  378. send_next:
  379.                 add     bx,8
  380.                 cmp     bx,tbfend       ;end of ring?
  381.                 jb      xmt_nxt_ok      ;no...
  382.                 mov     bx,tbfstart     ;restart at first descriptor
  383. xmt_nxt_ok:
  384.                 mov     tbfcurr,bx
  385.  
  386. send_done:
  387.                 test    al,TBerr        ;were there problems?
  388.                 jnz     send_err
  389.                 clc
  390.                 ret
  391.  
  392. send_err:
  393.                 call    count_out_err
  394.                 stc
  395.                 ret
  396. send_pkt        endp
  397.  
  398.  
  399.         public  get_address
  400. get_address:
  401. ;get the address of the interface.
  402. ;enter with es:di -> place to get the address, cx = size of address buffer.
  403. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  404.         assume  ds:code
  405.         cmp     cx,EADDR_LEN
  406.         jnb     get_addr_ok             ;buffer ok
  407.         stc
  408.         ret
  409.  
  410. get_addr_ok:
  411.         push    si
  412.         mov     si,offset IBpadr
  413.         rep     movsb
  414.         pop     si
  415.         mov     cl,EADDR_LEN
  416.         clc
  417.         ret
  418.  
  419.  
  420.  
  421.         public  set_address
  422. set_address:
  423. ;enter with ds:si -> Ethernet address, CX = length of address.
  424. ;exit with nc if okay, or cy, dh=error if any errors.
  425.         assume  ds:nothing
  426.         cmp     cx,EADDR_LEN
  427.         jnb     set_addr_ok             ;buffer ok
  428.         mov     dh,BAD_ADDRESS
  429.         stc
  430.         ret
  431.  
  432. set_addr_ok:
  433.         assume  es:nothing
  434.         clc
  435.         ret
  436.  
  437.  
  438. reset_mode      proc    near
  439. ; stop and restart the receiver
  440.                 call    reset_interface         ;stop it
  441.                 mov     bx,c0_INIT              ;re-init
  442.                 call    wrcsr0
  443.                 mov     cx,-1                   ;wait until done
  444. rm_lp:
  445.                 call    rdcsr0
  446.                 test    ax,c0_IDON              ;ok?
  447.                 jnz     rm_IDON                 ;yes...
  448.                 loop    rm_lp                   ;else continue
  449.  
  450. rm_IDON:
  451.                 mov     bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON
  452.                 call    wrcsr0                  ;start the receiver
  453.                 ret
  454. reset_mode      endp
  455.  
  456.  
  457. rcv_mode_1:
  458.                 mov     IBmode,0003h
  459.                 jmp     reset_mode
  460.  
  461.  
  462. rcv_mode_3:
  463.                 mov     IBmode,0
  464.                 jmp     reset_mode
  465.  
  466. rcv_mode_6:
  467.                 mov     IBmode,8000h
  468.                 jmp     reset_mode
  469.  
  470.  
  471.         public  set_multicast_list
  472. set_multicast_list:
  473. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  474. ;return nc if we set all of them, or cy,dh=error if we didn't.
  475.         mov     dh,NO_MULTICAST
  476.         stc
  477.         ret
  478.  
  479.  
  480.     public    terminate
  481. terminate:
  482.     ret
  483.  
  484.  
  485.         public  get_multicast_list
  486. get_multicast_list:
  487. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  488. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  489. ;return cy, NO_MULTICAST if we don't implement multicast.
  490.         mov     dh,NO_MULTICAST
  491.         stc
  492.         ret
  493.  
  494.  
  495.  
  496.         public  reset_interface
  497. reset_interface proc    near
  498. ;reset the interface.
  499.                 assume  ds:code
  500.                 mov     bx,c0_STOP+c0_FIX
  501.                 call    wrcsr0
  502.                 ret
  503. reset_interface endp
  504.  
  505.  
  506. ;called when we want to determine what to do with a received packet.
  507. ;enter with cx = packet length, es:di -> packet type.
  508.         extrn   recv_find: near
  509.  
  510. ;called after we have copied the packet into the buffer.
  511. ;enter with ds:si ->the packet, cx = length of the packet.
  512.         extrn   recv_copy: near
  513.  
  514.  
  515.         public  recv
  516. recv    proc    near
  517. ;called from the recv isr.  All registers have been saved, and ds=cs.
  518. ;Upon exit, the interrupt will be acknowledged.
  519.         assume  ds:code
  520.  
  521.         call    rdcsr0                  ;obtain interrupting status
  522.         mov     rcv_csr0,ax             ;save
  523.         and     ax,0ffffh-c0_INEA       ;disable interrupts
  524.         mov     bx,ax
  525.         call    wrcsr0                  ;clear acknowledged i-sources
  526.         test    bx,c0_MISS              ;out of buffers?
  527.         jz      rcv_noerr               ;no...
  528.         call    count_in_err
  529.  
  530. rcv_noerr:
  531.         test    rcv_csr0,c0_RINT        ;received a packet
  532.         jz      rcv_norint
  533. rcv_rint:
  534.         call    do_rcv                  ;process...
  535.  
  536. rcv_norint:
  537.         mov     bx,c0_INEA              ;re-enable interrupts
  538.         call    wrcsr0
  539.  
  540.  
  541. ;The following is currently disabled because of perhaps
  542. ;unrelated problems: the clearing of the Int-sources is still
  543. ;done immediately after the interrupt....
  544. ;
  545. ;The interrupt sources are cleared very late increasing the
  546. ;possibility that we may handle several incoming packets without
  547. ;the processor being interrupted. However, this makes it possible
  548. ;that we miss an interrupt - so we have to check twice.
  549.  
  550. ;       mov     bx,rcv_csr0             ;re-enable interrupts and
  551. ;       call    wrcsr0                  ;clear acknowledged i-sources
  552. ;       mov     bx,rbfcurr              ;current receive descriptor
  553. ;       test    RBflags[bx],RBown       ;could have missed incoming pkt
  554. ;       jnz     rcv_ret                 ;no...
  555. ;       call    do_rcv                  ;process it, int already acked
  556.  
  557. rcv_ret:
  558.         ret
  559. recv    endp
  560.  
  561.  
  562.  
  563. do_rcv          proc    near
  564.                 mov     bx,rbfcurr              ;address descriptor
  565.  
  566. ;The following loop continues to check the next descriptor for
  567. ;work. It can therefore happen that a we already check descriptors
  568. ;while the Lance has not yet finished receiving the whole packet on
  569. ;remaining descriptors!
  570.  
  571. rcv_lp:
  572.                 mov     al,RBflags[bx]
  573.                 test    al,RBown                ;something in buffer?
  574.                 jz      rcv_dobuf               ;yes...
  575.                 ret                             ;else return
  576.  
  577. rcv_dobuf:
  578.                 test    al,RBstp                ;start of packet?
  579.                 jz      rcv_next_bx             ;no, unrolling err chain
  580.  
  581. rcv_GetEnp:
  582.                 test    al,RBerr                ;anything wrong with it?
  583.                 jz      rcv_ge_noerr            ;no, seems ok.
  584.                 mov     dl,al                   ;copy flags
  585.                 and     dl,RBenp+RBoflo
  586.                 cmp     dl,RBenp+RBoflo         ;this is no error!
  587.                 je      rcv_enp                 ;get length
  588.                 jmp     short rcv_do_err
  589. rcv_ge_noerr:
  590.                 test    al,RBenp                ;end of packet?
  591.                 jnz     rcv_enp                 ;yes, get length
  592.  
  593. ; not on last segment
  594. ;               test    al,RBoflo               ;possible error
  595. ;               jnz     rcv_do_err_0
  596.                 add     bx,8                    ;to next descriptor
  597.                 cmp     bx,tbfstart             ;wrap around?
  598.                 jb      rcv_ge_bx               ;no...
  599.                 mov     bx,rbfstart
  600. rcv_ge_bx:
  601.                 cmp     bx,rbfcurr              ;make sure we don't loop!
  602.                 je      rcv_do_err_0            ;this is nonsense
  603.                 mov     al,RBflags[bx]          ;get new flags
  604.                 test    al,RBown                ;must be ours!
  605.                 jz      rcv_GetEnp              ;ok, go ahead
  606. ; when we arrive here, we are processing a packet that has not yet
  607. ; been completely received. Leave everything as it is, we are
  608. ; guaranteed to check again, when the interrupt comes in at the
  609. ; latest.
  610.                 ret
  611. rcv_do_err_0:
  612. ; should count it somewhere else, but where?
  613.  
  614. rcv_do_err:
  615.                 call    count_in_err
  616.  
  617. rcv_next:
  618.                 mov     bx,rbfcurr              ;restore current desc
  619. rcv_next_bx:
  620.                 call    rcv_nxt_d               ;next descriptor
  621.                 jmp     rcv_lp
  622.  
  623.  
  624. ;end of packet, check errors and obtain length
  625. rcv_enp:
  626. ;               test    al,RBfram+RBcrc         ;possible errors?
  627. ;               jnz     rcv_do_err
  628.                 mov     cx,RBmcnt[bx]           ;message length
  629.                 sub     cx,4                    ;strip FCS
  630.                 mov     bx,rbfcurr              ;restore descriptor addr
  631.                 cmp     cx,GIANT                ;reasonable size?
  632.                 jg      rcv_do_err              ;rubbish!
  633.                 jcxz    rcv_next                ;nothing to do...
  634.                 mov     pklen,cx                ;save packet length
  635.                 mov     pklen_rem,cx            ;remains to be rcvd
  636.  
  637.                 call    rcv_getaddr
  638.  
  639.                 mov     di,ax
  640.                 mov     es,dx
  641.                 add     di,EADDR_LEN*2          ;point to type field
  642.  
  643.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  644.     mov    ax, es:[di]
  645.     xchg    ah, al
  646.     cmp     ax, 1500
  647.     ja    BlueBookPacket
  648.     inc    di            ;set di to 802.2 header
  649.     inc    di
  650.     mov    dl, IEEE8023
  651. BlueBookPacket:
  652.  
  653.                 call    recv_find               ;want this packet?
  654.  
  655.                 mov     ax,es
  656.                 or      ax,di
  657.                 mov     bx,rbfcurr              ;restore in any case!
  658.                 jz      rcv_next_bx             ;no buffer, give up
  659.  
  660.                 push    es
  661.                 push    di
  662.  
  663.  
  664. rcv_seg_lp:
  665. ; the packet's segments are copied into the client's buffer.
  666. ; The calculated length did not include the 4 byte fcs. Care must
  667. ; be taken not to copy the fcs, which may (in the worst case) be
  668. ; part of the last two segments!
  669.  
  670.                 test    RBflags[bx],RBenp       ;packet ends here?
  671.                 jz      rcv_seg_l_buf           ;no, use buffer size
  672.                 mov     cx,pklen_rem            ;remaining msg length
  673.                 or      cx,cx                   ;still data?
  674.                 jle     rcv_done                ;no, just part of fcs
  675.                 jmp     short rcv_seg_l_ok
  676.  
  677. rcv_seg_l_buf:
  678.                 mov     cx,RBbcnt[bx]           ;buffer size
  679.                 neg     cx                      ;it's in two's complement
  680.                 sub     pklen_rem,cx            ;correct remaining len
  681.                 jnl     rcv_seg_l_ok            ;use whole buffer
  682. ; the current buffer contains part of the fcs...
  683.                 add     cx,pklen_rem            ;use only data part
  684.  
  685. rcv_seg_l_ok:
  686.                 lds     si,rcvbuffp             ;point to buffer
  687.                 assume  ds:nothing
  688.  
  689. ; The segment is copied two bytes at a time; we know that the input
  690. ; buffer starts on an even address.
  691.                 shr     cx,1            ;CF set when not even length!
  692.                 jz      rcv_last
  693.                 rep     movsw                   ;copy the packet
  694. rcv_last:
  695.                 jnc     rcv_moved
  696.                 movsb                           ;copy last byte
  697.  
  698. rcv_moved:
  699.                 push    cs
  700.                 pop     ds
  701.                 assume  ds:code
  702.  
  703.                 test    RBflags[bx],RBenp       ;end of packet?
  704.                 jnz     rcv_done                ;yes...
  705.  
  706.                 call    rcv_nxt_d               ;to next descriptor
  707.                 call    rcv_getaddr             ;next buffer addr
  708.                 jmp     rcv_seg_lp
  709.  
  710. rcv_done:
  711.                 mov     cx,pklen
  712.                 pop     si                      ;restore buffer addr
  713.                 pop     ds
  714.                 assume  ds:nothing
  715.  
  716.                 call    recv_copy               ;wake up client
  717.  
  718.                 push    cs
  719.                 pop     ds
  720.                 assume  ds:code
  721.  
  722. ;test           jmp     rcv_next                ;do next one
  723.                 mov     bx,rbfcurr
  724.                 call    rcv_nxt_d
  725.                 ret
  726.  
  727. do_rcv          endp
  728.  
  729.  
  730.         public  recv_exiting
  731. recv_exiting:
  732. ;called from the recv isr after interrupts have been acknowledged.
  733. ;Only ds and ax have been saved.
  734.         assume  ds:nothing
  735.         ret
  736.  
  737.  
  738. ; Most of the initialisation code is used only once and can be
  739. ; dicarded when init finishes, but not this:
  740. ; we formatted the buffer descriptors (a maximum space for
  741. ; that could be provided), but where could we place this code
  742. ; if buffers are allocated immediately afterwards?
  743. ; Too dangerous in the buffer area, since we will start the receiver now.
  744. ; Possible alternative: relocate to an address after the buffers, but
  745. ; since it's only a few bytes...
  746.  
  747. eto_go:
  748.         assume  ds:code
  749.         call    wrcsr           ;start the Lance
  750.  
  751.         pop     dx              ;get our ending paragraph
  752.         mov     ah,31h
  753.         int     21h             ;terminate, stay resident
  754.  
  755.  
  756. ; Provide maximum space for buffer descriptors before more
  757. ; discardable initialisation code starts, since the decriptors
  758. ; must be formatted. Buffers may follow immediately afterwards,
  759. ; but will not be used until the receiver is started.
  760.  
  761. ; All resident code and data must be before this label!
  762. ; on quadword boundary...
  763.                 org     begin+( (($-begin+7)/8)*8 )
  764. FirstDescr      db      ((128+128)*8) dup (0)
  765.  
  766.  
  767.  
  768.         public  usage_msg
  769. usage_msg   db  "usage: ISOLINK [-n] [-d] [-w] <packet_int_no> <options>",CR,LF
  770.         db      "options:       [defaults]",CR,LF
  771.         db      "  /D<DMA channel #> [0]",CR,LF
  772.         db      "  /I<hw-int-level> [10]",CR,LF
  773.         db      "  /P<I/O port address> [(8)280]",CR,LF
  774.         db      "  /R<# recv buffs> <recv buff size> [16 256]",CR,LF
  775.         db      "  /T<# xmit buffs> <xmit buff size> [1 0]",CR,LF
  776.         db      "  /X (requires himem.sys installed)",CR,LF
  777.         db      "$"
  778.  
  779.  
  780.  
  781.  
  782.         public  copyright_msg
  783. copyright_msg   db  "Packet driver for BICC 4110-2/3 ISOLINK controllers,"
  784.         db  "version ",'0'+majver,".",'0'+version,CR,LF
  785.                 db  "Written by R.Toebbicke, CERN, Switzerland",CR,LF
  786.  db "*     Copyright CERN, Geneva 1990 - Copyright and any other",CR,LF
  787.  db "*     appropriate legal protection of these computer programs",CR,LF
  788.  db "*     and associated documentation reserved in all countries",CR,LF
  789.  db "*     of the world.",CR,LF,'$'
  790.  
  791.  
  792.  
  793. int_no_name     db      "Interrupt number $"
  794. BaseName        db      "I/O Port address $"
  795. BasePrt         dw      08280h,0
  796. DMAName         db      "DMA channel number $"
  797. DMAPrt          dw      0,0
  798.  
  799.         extrn   our_isr: near, their_isr: dword
  800.         extrn   packet_int_no: byte
  801.         extrn   phd_environ: word
  802.         extrn   decout: near
  803.  
  804. rcv_buffno      dw      16,0
  805. rcv_buffnoname  db      "Number of receive buffers $"
  806. rcv_bufflog     db      4
  807. rcv_buffsz      dw      256,0
  808. rcv_buffszname  db      "Receive buffer size $"
  809. xmt_buffno      dw      1,0
  810. xmt_buffnoname  db      "Number of transmit buffers $"
  811. xmt_bufflog     db      0
  812. xmt_buffsz      dw      0,0
  813. xmt_buffszname  db      "Transmit buffer size $"
  814.  
  815. orgseg          dw      ?
  816.  
  817. linaddrL        dw      0
  818. linaddrH        dw      0
  819.  
  820. ; keep these two together!
  821. HMAaddr         dw      00010h
  822. HMAaddrS        dw      0FFFFh
  823.  
  824. XMSctl          dd      ?
  825.  
  826. PS2IO           dw      08280h, 09250h, 0a390h, 0b1d0h
  827. PS2INT          db      9, 10, 11, 15, 3, 4, 5, 0
  828.  
  829.  
  830.         extrn   set_recv_isr: near
  831.  
  832. ;enter with si -> argument string, di -> word to store.
  833. ;if there is no number, don't change the number.
  834.     extrn    get_number: near
  835.  
  836. ;enter with dx -> name of word, di -> dword to print.
  837.     extrn    print_number: near
  838.  
  839.         extrn   skip_blanks: near
  840.  
  841. argerr          db      "Error in options: '"
  842. argerrc         db      " "
  843.                 db      "'.",CR,LF,"$"
  844.  
  845. parse_err       db      0
  846.  
  847.  
  848.         public  parse_args
  849. parse_args      proc    near
  850. ; If we run on a PS/2, read the default configuration from the POS regs
  851.  
  852.     test    sys_features,MICROCHANNEL
  853.     jnz    do_mc_defaults
  854.     jmp    parse_args_l
  855. do_mc_defaults:
  856.  
  857.                 mov     bx,08h                  ;1st slot
  858. pa_slot_l:
  859.                 mov     dx,96h
  860.                 mov     ax,bx
  861.                 out     dx,al                   ;put in setup mode
  862.                 mov     dx,101h
  863.                 in      al,dx
  864.                 xchg    al,ah                   ;high id byte
  865.                 dec     dx
  866.                 in      al,dx                   ;low id byte
  867.                 cmp     ax,0808h                ;ISOLINK card?
  868.                 je      pa_found_iso            ;yes...
  869.                 inc     bx                      ;next slot
  870.                 cmp     bx,0fh                  ;too far?
  871.                 jna     pa_slot_l               ;no, try next
  872.                 mov     dx,96h
  873.                 xor     al,al
  874.                 out     dx,al                   ;exit setup mode
  875.                 jmp     parse_args_l
  876.  
  877. pa_found_iso:
  878.                 mov     dx,102h
  879.                 in      al,dx                   ;get I/O address code
  880.                 xor     ah,ah
  881.                 and     al,6
  882.                 mov     bx,ax
  883.                 mov     ax,PS2IO[bx]            ;I/O port address
  884.                 mov     BasePrt,ax
  885.  
  886.                 mov     dx,104h
  887.                 in      al,dx
  888.                 xor     ah,ah
  889.                 shr     al,5                    ;isolate interrupt bits
  890.                 mov     bx,ax
  891.                 mov     al,PS2INT[bx]           ;interrupt number
  892.                 mov     int_no,ax
  893.  
  894.  
  895. parse_args_l:
  896.         call    skip_blanks
  897.         cmp     al,CR           ;end of args?
  898.         je      pa_ret          ;yes...
  899.         cmp     al,'/'          ;option following?
  900.         je      pa_doopt        ;yes
  901.  
  902. pa_err:
  903.         mov     argerrc,al
  904.         mov     dx,offset argerr
  905.  
  906. pa_err2:
  907.         mov     ah,9
  908.         int     21h             ;print error message
  909.         mov     parse_err,1     ;indicate error
  910. pa_ret:
  911.         ret
  912.  
  913. pa_doopt:
  914.         inc     si
  915.         lodsb                   ;get option byte
  916.         cmp     al,'a'          ;in lowercase range?
  917.         jna     pa_upper
  918.         sub     al,20h          ;convert to uppercase
  919. pa_upper:
  920.         cmp     al,'I'
  921.         je      pa_doInt
  922.         cmp     al,'P'
  923.         je      pa_doPort
  924.         cmp     al,'D'
  925.         je      pa_doDMA
  926.         cmp     al,'R'
  927.         je      pa_doRcv
  928.         cmp     al,'T'
  929.         je      pa_doTrans
  930.         cmp     al,'X'                  ;into extended memory?
  931.         je      pa_doext
  932.         jmp     pa_err
  933.  
  934. pa_doInt:
  935.         mov     di,offset int_no
  936.         call    get_number
  937.         jmp     parse_args_l
  938.  
  939. pa_doPort:
  940.         mov     di,offset BasePrt
  941.         call    get_number
  942.         jmp     parse_args_l
  943.  
  944. pa_doDMA:
  945.         mov     di,offset DMAPrt
  946.         call    get_number
  947.         jmp     parse_args_l
  948.  
  949.  
  950. pa_doRcv:
  951.         mov     di,offset rcv_buffno
  952.         call    get_number
  953.  
  954.         mov     di,offset rcv_buffsz
  955.         call    get_number
  956.         jmp     parse_args_l
  957.  
  958.  
  959. pa_doTrans:
  960.         mov     di,offset xmt_buffno
  961.         call    get_number
  962.  
  963.         mov     di,offset xmt_buffsz
  964.         call    get_number
  965.         jmp     parse_args_l
  966.  
  967.  
  968. pa_doext:                       ;set up for HMA
  969.         or      options,options_HMA   ;indicate we want to run up there
  970.         jmp     parse_args_l
  971.  
  972.  
  973. parse_args      endp
  974.  
  975.  
  976.     public    print_parameters
  977. print_parameters    proc
  978.         mov     di,offset int_no
  979.         mov     dx,offset int_no_name
  980.         call    print_number
  981.  
  982.         mov     di,offset BasePrt
  983.         mov     dx,offset BaseName
  984.         call    print_number
  985.  
  986.         mov     di,offset DMAPrt
  987.         mov     dx,offset DMAName
  988.         call    print_number
  989.  
  990.         mov     di,offset rcv_buffno
  991.         mov     dx,offset rcv_buffnoname
  992.         call    print_number
  993.  
  994.         mov     di,offset rcv_buffsz
  995.         mov     dx,offset rcv_buffszname
  996.         call    print_number
  997.  
  998.         mov     di,offset xmt_buffno
  999.         mov     dx,offset xmt_buffnoname
  1000.         call    print_number
  1001.  
  1002.         mov     di,offset xmt_buffsz
  1003.         mov     dx,offset xmt_buffszname
  1004.         call    print_number
  1005.  
  1006.     ret
  1007.  
  1008. print_parameters    endp
  1009.  
  1010.  
  1011.  
  1012.  
  1013. inv_DMA         db      "Invalid DMA channel number.",CR,LF,"$"
  1014. init_errmsg     db      "Lance initialisation failed.",CR,LF,"$"
  1015. inv_buff        db      "Invalid buffer specification.",CR,LF,"$"
  1016. HMAnoHIMEM      db      "HMA not available: HIMEM.SYS not installed.",CR,LF,"$"
  1017. HMAnotavail     db      "HMA not available.",CR,LF,"$"
  1018. HMAalloc        db      "Using extended memory (HMA).",CR,LF,"$"
  1019. HMAtoobig       db      "Buffers exceed HMA size.",CR,LF,"$"
  1020. HMAmsg_1        db      "/X configured $"
  1021. HMAmsg_2        db      " receive buffers of length $"
  1022. HMAmsg_3        db      "."
  1023. crlf_msg    db    CR,LF,"$"
  1024.  
  1025. really_bad_msg    db    "This driver may be buggy.  Do you really want to run it (y/n)? ",'$'
  1026.  
  1027.                 public  etopen
  1028. etopen          proc    near
  1029.                 assume  ds:code
  1030.  
  1031.         mov    dx,offset really_bad_msg
  1032.         mov    ah,9
  1033.         int    21h
  1034.  
  1035.         mov    ah,7
  1036.         int    21h
  1037.  
  1038.         cmp    al,'y'
  1039.         je    etopen_1
  1040.         cmp    al,'Y'
  1041.         je    etopen_1
  1042.         int    20h
  1043. etopen_1:
  1044.  
  1045.         mov    dx,offset crlf_msg
  1046.         mov    ah,9
  1047.         int    21h
  1048.  
  1049.                 test    parse_err,0ffh  ;any parsing error?
  1050.                 jnz     eto_errexit2    ;yes, give up
  1051.  
  1052.                 cmp     packet_int_no,0
  1053.                 mov     dx,offset usage_msg
  1054.                 jz      eto_errexit
  1055.  
  1056.  
  1057.  
  1058. ; check DMA port
  1059.                 mov     ax,DMAPrt
  1060.                 or      ax,ax
  1061.                 jb      eto_invalid_DMA ;should not be negative
  1062.                 cmp     ax,3
  1063.                 jna     eto_DMA_ok
  1064.  
  1065. eto_invalid_DMA:
  1066.                 mov     dx,offset inv_DMA
  1067.  
  1068. eto_errexit:
  1069.                 mov     ah,9
  1070.                 int     21h
  1071. eto_errexit2:
  1072.                 stc
  1073.                 ret
  1074.  
  1075. eto_DMA_ok:
  1076. ; check receive buffers
  1077.                 mov     bx,rcv_buffno
  1078.                 call    do_power_of_2
  1079.                 cmp     ax,128
  1080.                 jg      eto_inv_Buff
  1081.                 or      ax,ax                   ;must have something!
  1082.                 jz      eto_inv_Buff
  1083.                 mov     rcv_bufflog,cl
  1084.                 mov     rcv_buffno,ax
  1085.  
  1086.                 mov     ax,rcv_buffsz   ;check buffer size
  1087.                 cmp     ax,100          ;at least that big
  1088.                 jg      eto_rcvsz_1
  1089.                 mov     ax,100
  1090. eto_rcvsz_1:
  1091.                 cmp     ax,GIANT+4      ;biggest packet plus fcs
  1092.                 jl      eto_rcvsz_2     ;does not exceed
  1093.                 mov     ax,GIANT+4      ;take maximum
  1094. eto_rcvsz_2:
  1095.                 mov     rcv_buffsz,ax
  1096.  
  1097. ; check transmit buffers
  1098.                 mov     bx,xmt_buffno
  1099.                 call    do_power_of_2
  1100.                 or      ax,ax                   ;must have something!
  1101.                 jz      eto_inv_Buff
  1102.                 cmp     ax,128
  1103.                 jna     eto_xmt_buffok
  1104.  
  1105. eto_inv_Buff:
  1106.                 mov     dx,offset inv_Buff
  1107.                 jmp     eto_errexit
  1108.  
  1109. eto_xmt_buffok:
  1110.                 mov     xmt_bufflog,cl
  1111.                 mov     xmt_buffno,ax
  1112.  
  1113.                 mov     ax,xmt_buffsz   ;check buffer size
  1114.                 cmp     ax,RUNT         ;at least that big
  1115.                 jg      eto_xmtsz_1
  1116.                 mov     ax,0            ;else don't use
  1117. eto_xmtsz_1:
  1118.                 cmp     ax,GIANT        ;biggest packet w/o fcs
  1119.                 jl      eto_xmtsz_2     ;does not exceed
  1120.                 mov     ax,GIANT        ;take maximum
  1121. eto_xmtsz_2:
  1122.                 mov     xmt_buffsz,ax
  1123.                 mov     xmt_buffsz_r,ax ;again for our resident part
  1124.                 neg     ax
  1125.                 mov     xmt_buffsz_rn,ax ;times -1 for resident part
  1126.  
  1127. ; set RAP & RDP addresses
  1128.                 mov     ax,BasePrt
  1129.                 add     ax,0ch
  1130.                 mov     RDP,ax
  1131.                 add     ax,02h
  1132.                 mov     RAP,ax
  1133.  
  1134.  
  1135. ; this code is from Russell Nelson's packet driver skeleton.
  1136. ; Need it here, since we won't return from etopen: as soon as the
  1137. ; receiver is started, this place may get clobbered with Ethernet packets
  1138.  
  1139.         mov     ah,35h                  ;remember their packet interrupt.
  1140.         mov     al,packet_int_no
  1141.         int     21h
  1142.         mov     their_isr.offs,bx
  1143.         mov     their_isr.segm,es
  1144.  
  1145.         mov     ah,25h                  ;install our packet interrupt
  1146.         mov     dx,offset our_isr
  1147.         int     21h
  1148.  
  1149. ; First of all: stop the Lance, sets required bits in CSR3 as well
  1150.                 call    reset_interface
  1151.  
  1152.                 call    set_recv_isr    ;intercept interrupts
  1153.  
  1154.  
  1155. ; Now we decide whether we will run in the HMA (above 1 MB) before
  1156. ; we do any calculations involving real addresses
  1157.  
  1158.                 test    options,options_HMA  ;will we?
  1159.                 jnz     eto_tryHMA      ;yes
  1160.                 jmp     eto_HMAok       ;no...
  1161.  
  1162. ; first check of HIMEM.SYS is installed and if we can globally
  1163. ; enable the HMA
  1164. eto_tryHMA:
  1165.                 mov     ax,4300h
  1166.                 int     2Fh             ; Is an XMS Driver installed?
  1167.                 mov     dx,offset HMAnoHIMEM    ;error message in case...
  1168.                 cmp     al,80h
  1169.                 jne     eto_noHMA       ;no...
  1170.                 mov     ax,4310h
  1171.                 int     2fh             ;obtain XMS control addr
  1172.                 mov     word ptr XMSctl,bx      ;save entry point
  1173.                 mov     word ptr XMSctl+2,es
  1174.  
  1175.                 mov     dx,0ffffh       ;allocate whole HMA
  1176.                 mov     ah,1
  1177.                 call    XMSctl
  1178.                 mov     dx,offset HMAnotavail   ;error msg in case...
  1179.                 cmp     ax,1
  1180.                 jne     eto_noHMA               ;not available
  1181.                 mov     ah,3                    ;global enable A20 line
  1182.                 call    XMSctl
  1183.                 cmp     ax,1                    ;ok?
  1184.                 je      eto_HMA_enabled
  1185.  
  1186. eto_noHMA:
  1187.                 mov     ah,9
  1188.                 int     21h                     ;error msg addr in dx!
  1189.                 and     options,not options_HMA ;turn off HMA bit
  1190.                 jmp     eto_HMAok               ;continue as usual
  1191.  
  1192. eto_HMA_enabled:
  1193. ;               mov     dx,offset HMAalloc
  1194. ;               mov     ah,9
  1195. ;               int     21h                     ;confirm
  1196.  
  1197.  
  1198. ; maximize the receive buffer space to utilise the whole HMA:
  1199. ;  1. calculate remaining space excluding receive buffers and descriptors
  1200. ;  2. start with 128 receive buffers
  1201. ;  3. calculate remaining space for buffers
  1202. ;  4. divide by number of buffers to obtain (even) buffer size
  1203. ;  5. if size inferior to defaulted or specified size half number
  1204. ;     of buffers and restart on step 2.
  1205.  
  1206.                 mov     bx,0fff0h       ;total HMA size
  1207.                 sub     bx,offset FirstDescr    ;minus resident code
  1208.  
  1209.                 mov     ax,xmt_buffsz   ;xmit buffer size
  1210.                 add     ax,8            ;plus descriptor
  1211.                 mul     xmt_buffno      ;=total xmit space
  1212.                 or      dx,dx           ;not more than 64k!
  1213.                 jnz     try_err         ;ooops
  1214.  
  1215.                 sub     bx,ax           ;remaining space without recv
  1216.                 jc      try_err         ;must be positive!
  1217.  
  1218.                 mov     cx,128          ;try 128 buffers
  1219. try_lp:
  1220.                 mov     ax,cx           ;number of buffers
  1221.                 shl     ax,3            ;8 bytes long
  1222.                 sub     ax,bx
  1223.                 neg     ax              ;remaining space for buffers
  1224.  
  1225.                 xor     dx,dx           ;accumulator extension
  1226.                 div     cx              ;calculate buffer length
  1227.                 and     ax,0fffeh       ;even length
  1228.                 cmp     ax,rcv_buffsz   ;long enough?
  1229.                 jnb     try_ok          ;yes...
  1230.                 shr     cx,1            ;else half number of buffers
  1231.                 jnz     try_lp          ;and retry
  1232.  
  1233. try_err:
  1234.                 mov     dx,offset HMAtoobig
  1235.                 jmp     eto_errexit
  1236.  
  1237. try_ok:
  1238.                 cmp     ax,GIANT+4      ;maximum size
  1239.                 jng     try_ok_2        ;does not exceed
  1240.                 mov     ax,GIANT+4      ;else maximum length
  1241. try_ok_2:
  1242.                 mov     rcv_buffno,cx
  1243.                 mov     rcv_buffsz,ax
  1244.                 mov     bx,cx
  1245.                 call    do_power_of_2   ;have to do it again
  1246.                 mov     rcv_bufflog,cl
  1247.  
  1248.  
  1249.  
  1250.                 mov     dx,offset HMAmsg_1
  1251.                 mov     ah,9
  1252.                 int     21h
  1253.  
  1254.                 mov     ax,rcv_buffno
  1255.                 xor     dx,dx
  1256.                 call    decout
  1257.  
  1258.                 mov     dx,offset HMAmsg_2
  1259.                 mov     ah,9
  1260.                 int     21h
  1261.  
  1262.                 mov     ax,rcv_buffsz
  1263.                 xor     dx,dx
  1264.                 call    decout
  1265.  
  1266.                 mov     dx,offset HMAmsg_3
  1267.                 mov     ah,9
  1268.                 int     21h
  1269.  
  1270.  
  1271. ; la demarche a suivre:
  1272. ; we copy ourselves into the HMA completely, format all the
  1273. ; descriptors, correct the interrupt addr and exit to DOS
  1274.  
  1275.                 mov     ax,cs
  1276.                 mov     orgseg,ax       ;save original segment
  1277.                 les     di,dword ptr HMAaddr ;that's where we will be
  1278.                 mov     cx,offset end_code  ;length(!) of code to be copied
  1279.                 mov     si,10h          ;start at offset 10
  1280.                 sub     cx,si           ;correct length
  1281.                 rep     movsb           ;copy us
  1282.                 push    HMAaddrS        ;our new segment
  1283. ; careful: here comes a jump!
  1284.                 call   setcs            ;we're in the HMA
  1285.                 push    cs
  1286.                 pop     ds              ;our data as well
  1287.  
  1288.  
  1289.  
  1290. eto_HMAok:
  1291. ; get linear address for receive buffer descriptor start
  1292.                 push    ds
  1293.                 mov     ax,offset FirstDescr
  1294.                 pop     dx
  1295.                 call    seg2lin
  1296.  
  1297. ; Store in Init Block
  1298.                 mov     IBrdraL,ax
  1299.                 mov     IBrdraH,dx
  1300.  
  1301. ; calculate linear address of first buffer
  1302.                 mov     bx,offset FirstDescr
  1303.                 mov     rbfstart,bx
  1304.                 mov     rbfcurr,bx
  1305.  
  1306.                 mov     ax,rcv_buffno
  1307.                 push    ds
  1308.                 pop     dx
  1309.                 add     ax,xmt_buffno   ;result is still in segment
  1310.                 shl     ax,3            ;times eight
  1311.                 add     ax,bx           ;won't leave segment!
  1312.                 call    seg2lin         ;convert to linear addr
  1313.                 mov     linaddrL,ax     ;first available buffer addr
  1314.                 mov     linaddrH,dx
  1315.  
  1316. ; format receive buffer descriptors
  1317.                 mov     si,rcv_buffsz   ;buffer size
  1318.                 mov     cx,rcv_buffno   ;number of buffers
  1319.                 mov     dl,RBown        ;flags
  1320. eto_rcvloop:
  1321.                 call    format_descr
  1322.                 add     bx,8
  1323.                 loop    eto_rcvloop
  1324.  
  1325.  
  1326. ;set transmit descriptor ring address
  1327.                 push    ds
  1328.                 mov     ax,bx
  1329.                 pop     dx
  1330.                 call    seg2lin
  1331.                 mov     IBtdraL,ax
  1332.                 mov     IBtdraH,dx
  1333.  
  1334. ; format transmit buffer descriptors
  1335.                 mov     tbfstart,bx             ;remember start
  1336.                 mov     tbfcurr,bx
  1337.                 mov     dl,0                    ;initial flags
  1338.                 mov     cx,xmt_buffno           ;number of buffers
  1339.                 mov     si,xmt_buffsz           ;buffer size
  1340. eto_xmtloop:
  1341.                 call    format_descr
  1342.                 add     bx,8
  1343.                 loop    eto_xmtloop
  1344.                 mov     tbfend,bx               ;remember end
  1345.  
  1346.  
  1347. ; finish initialisation block
  1348.                 mov     al,rcv_bufflog  ;# of rcv buffers
  1349.                 shl     al,5
  1350.                 mov     IBrdraHF,al
  1351.  
  1352.                 mov     al,xmt_bufflog  ;# of xmt buffers
  1353.                 shl     al,5
  1354.                 mov     IBtdraHF,al
  1355.  
  1356. ; copy Ethernet address out of ROM
  1357.                 mov     cx,6
  1358.                 push    ds
  1359.                 pop     es
  1360.                 mov     di,offset IBpadr
  1361.                 mov     dx,BasePrt
  1362. eto_addrloop:
  1363.                 in      ax,dx
  1364.                 inc     dx
  1365.                 inc     dx
  1366.                 stosb
  1367.                 loop    eto_addrloop
  1368.  
  1369. ; init DMA controller
  1370.                 test    sys_features,MICROCHANNEL ;running on a PS/2?
  1371.                 jnz     eto_DMA_done    ;yes, no DMA
  1372.                 mov     al,0d0h         ;mode reg bits
  1373.                 mov     dx,0bh          ;addr of mode reg
  1374.                 or      al,byte ptr DMAPrt   ;or in DMA number
  1375.                 out     dx,al
  1376.                 jmp     $+2
  1377.                 and     al,3            ;leave only DMA channel #
  1378.                 mov     dx,0ah          ;mask register addr
  1379.                 out     dx,al           ;clear the DMA channel
  1380. eto_DMA_done:
  1381.  
  1382. ; set initialisation block addr
  1383.                 push    ds
  1384.                 pop     dx
  1385.                 mov     ax,offset IBmode
  1386.                 call    seg2lin
  1387.                 push    dx              ;don't loose it
  1388.                 mov     bx,ax
  1389.                 mov     ax,CSR1
  1390.                 call    wrcsr           ;low order 16 bits of addr
  1391.                 pop     bx
  1392.                 mov     ax,CSR2
  1393.                 call    wrcsr           ;high order bits
  1394.  
  1395. ; init the controller and wait for completion
  1396.                 mov     bx,c0_FIX+c0_INIT
  1397.                 call    wrcsr0
  1398.  
  1399.                 mov     cx,-1           ;wait for completion
  1400. eto_initlp:
  1401.                 call    rdcsr0
  1402.                 test    ax,c0_IDON      ;done?
  1403.                 jnz     eto_init_ok     ;good!
  1404.                 loop    eto_initlp
  1405.  
  1406.                 mov     dx,offset init_errmsg
  1407.                 call    outofHMA        ;get out of HMA
  1408.                 jmp     eto_errexit
  1409.  
  1410. eto_init_ok:
  1411.                 test    options,options_HMA ;are we in HMA?
  1412.                 jz      eto_tsr         ;no, use TSR code
  1413.                 xor     ax,ax
  1414. ; correct the packet and hardware interrupt addresses
  1415.                 mov     es,ax
  1416.                 xor     bh,bh
  1417.                 mov     bl,packet_int_no
  1418.                 shl     bx,2            ;point to interrupt vector
  1419.                 push    cs
  1420.                 pop     es:[bx+2]
  1421.  
  1422.                 mov     bx,int_no       ;card interrupt
  1423.                 add     bx,68h          ;assume above 8
  1424.                 cmp     bx,8+68h        ;is it?
  1425.                 jnb     eto_HMA_int_ok  ;yes...
  1426.                 sub     bx,60h          ;PS/2 can use interrupt < 8
  1427. eto_HMA_int_ok:
  1428.                 shl     bx,2            ;point to interrupt vector
  1429.                 push    cs
  1430.                 pop     es:[bx+2]
  1431.  
  1432. ; Now start the receiver and exit to DOS
  1433.         call    outofHMA                ;out of danger zone (buffers!)
  1434.         mov     bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON  ; ...SET...
  1435.         call    wrcsr0                                      ; ...GO!
  1436.         int     20h                     ;exit...
  1437.  
  1438.  
  1439. eto_tsr:
  1440. ;calculate end of resident part (relative to pgm start)
  1441.                 mov     ax,linaddrL
  1442.                 mov     dx,linaddrH
  1443.                 add     ax,15           ;round to paragraph
  1444.                 adc     dl,0
  1445.                 shr     ax,4
  1446.                 shl     dl,4
  1447.                 or      ah,dl
  1448.                 mov     dx,ds           ;minus pgm start addr
  1449.                 sub     ax,dx
  1450.                 push    ax              ;save the address
  1451.  
  1452.  
  1453. ; again some code from the packet driver skeleton...
  1454.  
  1455.         mov     ah,49h                  ;free our environment, because
  1456.         mov     es,phd_environ          ;  we won't need it.
  1457.         int     21h
  1458.  
  1459.         mov     bx,1                    ;get the stdout handle.
  1460.         mov     ah,3eh                  ;close it in case they redirected it.
  1461.         int     21h
  1462.  
  1463.         mov     ax,csr0                                     ; READY...
  1464.         mov     bx,c0_STRT+c0_INEA+c0_IDON+c0_RXON+c0_TXON  ; ...SET...
  1465.         jmp     eto_go                                      ; ...GO!
  1466. etopen          endp
  1467.  
  1468.  
  1469. do_power_of_2   proc    near
  1470. ; adjust bx to valid # of buffers.
  1471. ; on exit: ax=fitting number, cx=log2(ax)
  1472.                 mov     cx,7            ;allow 7 shifts
  1473.                 mov     ax,bx
  1474. dpw2_loop:
  1475.                 cmp     ax,1
  1476.                 je      dpw2_done
  1477.                 shr     ax,1
  1478.                 loop    dpw2_loop
  1479. dpw2_done:
  1480.                 mov     ax,7
  1481.                 sub     ax,cx           ;get number of shifts
  1482.                 mov     cx,ax
  1483.  
  1484.                 mov     ax,1
  1485.                 jcxz    dpw2_ret
  1486.                 shl     ax,cl
  1487. dpw2_ret:
  1488.                 ret
  1489. do_power_of_2   endp
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495. format_descr    proc    near
  1496. ; format buffer descriptor pointed to by [bx]
  1497. ; si=buffer size, dl=flags
  1498.                 push    dx              ;save flags
  1499.                 mov     ax,linaddrL     ;next available buffer addr
  1500.                 mov     dx,linaddrH
  1501.                 mov     RBadrL[bx],ax   ;buffer addr
  1502.                 mov     RBadrH[bx],dx
  1503.                 add     ax,si           ;point to next available addr
  1504.                 adc     dx,0
  1505.                 mov     linaddrL,ax
  1506.                 mov     linaddrH,dx
  1507.                 mov     ax,si           ;get buffer size
  1508. ;               or      ah,0f0h         ;reserved bits to 1
  1509.                 neg     ax              ;two's complement
  1510.                 mov     RBbcnt[bx],ax
  1511.                 pop     dx              ;restore flags
  1512.                 mov     RBflags[bx],dl
  1513.                 ret
  1514. format_descr    endp
  1515.  
  1516.  
  1517. outofHMA        proc    near    ;leave the HMA
  1518.                 test    options,options_HMA ;are we in it?
  1519.                 jz      ooHret          ;no...
  1520.                 push    orgseg
  1521.                 call    setcs
  1522.                 push    cs
  1523.                 pop     ds
  1524. ooHret:
  1525.                 ret
  1526. outofHMA        endp
  1527.  
  1528.  
  1529. setcs           proc    near
  1530.                 db      0cbh            ;RET FAR (!)
  1531. setcs           endp
  1532.  
  1533. end_code        equ     $
  1534.  
  1535. code    ends
  1536.         end
  1537.  
  1538.  
  1539.